#-*- coding:utf-8 -*-
import socket
import fcntl
import struct
import os
import xmlrpclib
import time
import threading

import minjson as json

import mon_agent_logger
from mon_agent_base import MonAgentException

logger = mon_agent_logger.instance()

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

def file2list(path):
    fd = open(path, 'r')
    lst = [[i.strip() for i in pair] for pair in [line.split(':') \
                        for line in fd if line.strip() != '']] 
    fd.close()
    return lst

def file2string(path):
    fd = open(path, 'r')
    astr = fd.read()
    fd.close()
    return astr

def system_(cmd):
    fd = os.popen(cmd)
    output = fd.read()
    fd.close()
    return output

def is_virt_plat():
    return os.access('/proc/xen', os.F_OK)

def getDictDeeply(dict_, keys):
    ret = dict_
    if type(keys) is str:
        ret = dict_[keys]
    else:
        keys = list(keys)
        for i in keys:
            ret = ret[i]

    return ret

def setDictDeeply(dict_, keys, val, createMidNodes=False):
    if type(keys) is str:
        dict_[keys] = val
    else:
        keys = list(keys)
        midKeys = keys[0:-1]
        theKey = keys[-1]
        sub = dict_
        for i in midKeys:
            try:
                sub = sub[i]
            except KeyError, e:
                if createMidNodes:
                    sub[i] = {}
                    sub = sub[i]
                else:
                    raise
        sub[theKey] = val


def remote_call(retry=3, timeout=5):
    wrapped_args = [retry, timeout]
    def try_call(procedure):
        def wrapper(*args, **kwargs):
            retry_ = retry = wrapped_args[0]
            timeout = wrapped_args[1]
            while retry:
                try:
                    result = procedure(*args, **kwargs)
                except socket.error, e:
                    logger.error("call %s(%s) failed, retry later..." \
                                 % (procedure.__name__, args))
                    retry -= 1
                    time.sleep(timeout)
                else:
                    logger.debug("call %s(%s) succeeded" % (procedure.__name__, args))
                    return True, result

            logger.error("retried call %s(%s) %d times and failed"
                         % (procedure.__name__, args, retry_))
            return False, None 

        return wrapper

    return try_call

def threadinglize(target_, tName=None, isDaemon_=True):
    def func_(*args_, **kwargs_):
        t = threading.Thread(target=target_, args=args_, kwargs=kwargs_)
        if isDaemon_:
            t.setDaemon(True)
        if tName:
            t.setName(tName)
        else:
            t.setName(target_.__name__)
        t.start()
    return func_

def load_config(config_file):
    try:
        fp = open(config_file)
    except IOError, e:
        if e.errno != 2:
            raise e
        else:
            raise MonAgentException, 'config file not found!'
    else:
        configstring = fp.read()
        config = decode(configstring)
        fp.close()
        return config

def decode(data):
    return json.read(data)

def encode(data):
    return json.write(data)

if __name__ == '__main__':
    import unittest

    class test_util(unittest.TestCase):

        def testFile2List(self):
            ret = file2list('/proc/cpuinfo')
            print ret

        def testGetDictDeeply(self):
            test = { '1': { '2': { '3': 4 } } }
            self.assertEquals(test['1']['2']['3'], \
                              getDictDeeply(test, ('1', '2', '3')))
            self.assertEquals(test['1'], \
                              getDictDeeply(test, '1'))

        def testSetDictDeeply(self):
            test = {}
            setDictDeeply(test, (1, 2, 3), 4, True)
            self.assertEquals(test[1][2][3], 4)
            setDictDeeply(test, (1, 2, 3), 'phsyco')
            self.assertEquals(test[1][2][3], 'phsyco')
            self.assertRaises(KeyError, setDictDeeply, test, (1,2,4,5), '')

        def testThreadinglize(self):
            def echo(i,j,msg='step'):
                for n in range(3):
                    print i,j,msg
                    print threading.currentThread().name
                    time.sleep(3)

            threadinglize(echo, 'ECHO', False)(1,2)
            for t in threading.enumerate():
                if t is not threading.currentThread():
                    t.join()

    
    unittest.main()
